# -*- coding: utf-8 -*-
import os
import csv
import time
from datetime import datetime


def str2time(str_val):
    return time.strptime(str_val, '%Y-%m-%d %H:%M:%S')


def str2timestamp(str_val):
    return time.mktime(str2time(str_val))


def timestamp2csv_time(ts):
    return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ts))


schema = list()
carVertexSchema = """
<label name="car">
        <properties>
            <property name="name" cardinality="single" dataType="string"/>
            <property name="timestamp" cardinality="single" dataType="date"/>
            <property name="duration" cardinality="single" dataType="int"/>
        </properties>
</label>
"""

snapshotSchema = """
<label name="snapshot">
        <properties>
            <property name="timestamp" cardinality="single" dataType="date"/>
        </properties>
</label>
"""

snapshotDetailSchema = """
<label name="snapshotDetail">
        <properties>
            <property name="type" cardinality="single" dataType="string"/>
            <property name="timestamp" cardinality="single" dataType="date"/>
            <property name="value" cardinality="single" dataType="double"/>
            <property name="description" cardinality="single" dataType="string"/>
        </properties>
</label>
"""

snapshotItem = list()
snapshotTemplate = """
<property name="{{name}}" cardinality="single" dataType="{{type}}"/>"""

snapshotDataSchema = """
<label name="snapshotData">
    <properties>{{propertiesList}}
    </properties>
</label>
"""

occurSchema = """
<label name="occur">
        <properties>
            <property name="timestamp" cardinality="single" dataType="date"/>
        </properties>
</label>
"""

eventSchema = """
<label name="event">
        <properties>
            <property name="type" cardinality="single" dataType="string"/>
            <property name="from_timestamp" cardinality="single" dataType="date"/>
            <property name="timestamp" cardinality="single" dataType="date"/>
            <property name="duration" cardinality="single" dataType="int"/>
            <property name="from" cardinality="single" dataType="double"/>
            <property name="to" cardinality="single" dataType="double"/>
            <property name="description" cardinality="single" dataType="string"/>
        </properties>
</label>
<label name="next">
    <properties></properties>
</label>
"""


class EventItem:

    def __init__(self, prop_name, old_timestamp, new_timestamp, old_value,
                 new_value):
        self.type = prop_name
        self.from_timestamp = old_timestamp
        self.timestamp = new_timestamp
        self.duration = new_timestamp - old_timestamp
        self.from_value = old_value
        self.to_value = new_value


class DetailItem:

    def __init__(self, prop_name, new_timestamp, value):
        self.type = prop_name
        self.timestamp = new_timestamp
        self.value = value
        self.description = prop_name + ":" + str(value)


class SnapshotItem:

    def __init__(self, car_id, snapshot_time):
        self.car_id = car_id
        self.snaphot_time = snapshot_time
        self.prop_list = dict()
        self.event_list = list()
        self.detail_list = list()
        self.detail_map = dict()
        self.detail_map2 = dict()


class PropItem:

    def __init__(self, car_id, prop_name, snapshot_time, occur_time, value,
                 prop_type):
        self.car_id = car_id
        self.prop_name = prop_name
        self.snapshot_time = snapshot_time
        self.occur_time = occur_time
        self.value = value
        self.type = prop_type

    def display(self):
        return self.car_id + " " + self.prop_name + " " + str(
            datetime.fromtimestamp(self.snapshot_time)) + " value " + self.value


carSnapshot = dict()
intervals = 10
eventInIntervals = [u'刹车', u'手刹']


def clear():
    carSnapshot.clear()
    snapshotItem.clear()
    schema.clear()


def add_event_from_record_list(record_list, prop_name, prop_value_data_type,
                               min_step, max_step):
    for i, record in enumerate(record_list):
        if i % max_step != 0 and prop_name not in eventInIntervals:
            continue
        event_list = list()
        car_i = record_list[i].car_id
        otime_i = record_list[i].occur_time
        time_i = otime_i - otime_i % intervals
        if i in [707 - 564, 707 - 565, 707 - 566] and prop_name == u'刹车':
            print(i)
        time_j0 = time_i
        for j in range(min_step, min(max_step, len(record_list) - i)):
            car_j = record_list[i + j].car_id
            otime_j = record_list[i + j].occur_time
            time_j = otime_j - otime_j % intervals
            if time_i != time_j or car_i != car_j:
                continue
            if record_list[i + j].value != record_list[i].value:
                if prop_value_data_type == "int":
                    if int((record_list[i].value)) != int(
                            (record_list[i + j].value)):
                        time_j0 = time_j
                        event_list.append(
                            EventItem(prop_name, otime_i, otime_j,
                                      int((record_list[i].value)),
                                      int((record_list[i + j].value))))
                else:
                    if abs(float(record_list[i].value) - float(
                            record_list[i + j].value)) > 0.1:
                        time_j0 = time_j
                        event_list.append(
                            EventItem(prop_name, otime_i, otime_j,
                                      float(record_list[i].value),
                                      float(record_list[i + j].value)))
        if len(event_list) > 0:
            carSnapshot[car_i][time_j0].event_list.append(event_list[-1])


def add_prop(prop_name, data_file_path, snapshot_time_offset, occur_time_offset,
             prop_value_offset,
             prop_value_data_type, add_change_event, add_snapshot_event=False,
             unique_offset=-1, prop_type_input="",
             add_snapshot_details=False):
    prop_schema = snapshotTemplate.replace("{{name}}", prop_name).replace(
        "{{type}}", prop_value_data_type)
    snapshotItem.append(prop_schema)
    prop_id = len(snapshotItem) - 1
    record_list = list()
    with open(data_file_path, 'rt') as csvrd:
        lines = csv.reader(csvrd, delimiter=',')
        first = True
        for line in lines:
            if first:
                first = False
                continue
            if len(line) < 4:
                continue
            snapshot_time = str2timestamp(line[snapshot_time_offset])
            occur_time = str2timestamp(line[occur_time_offset])
            val = line[prop_value_offset]
            prop_type = ""
            if unique_offset > 0:
                prop_type = line[unique_offset]
            if prop_type != prop_type_input:
                continue
            record_list.append(
                PropItem(line[0], prop_name, snapshot_time, occur_time, val,
                         prop_type))
    record_list.sort(key=lambda x: x.occur_time)
    snapshot_record_list = dict()
    for record in record_list:
        if record.car_id not in carSnapshot:
            carSnapshot[record.car_id] = dict()
        time_start_offset = record.occur_time - record.occur_time % intervals
        if time_start_offset not in snapshot_record_list:
            snapshot_record_list[time_start_offset] = list()
        if time_start_offset not in carSnapshot[record.car_id]:
            carSnapshot[record.car_id][time_start_offset] = SnapshotItem(
                record.car_id, time_start_offset)
        if prop_id not in carSnapshot[record.car_id][
            time_start_offset].prop_list:
            carSnapshot[record.car_id][time_start_offset].prop_list[
                prop_id] = record.value
        if add_snapshot_details:
            if prop_name not in carSnapshot[record.car_id][
                time_start_offset].detail_map2:
                carSnapshot[record.car_id][time_start_offset].detail_map2[
                    prop_name] = set()
            if prop_name not in carSnapshot[record.car_id][
                time_start_offset].detail_map or \
                    carSnapshot[record.car_id][time_start_offset].detail_map[
                        prop_name] != record.value:
                carSnapshot[record.car_id][time_start_offset].detail_map[
                    prop_name] = record.value
                carSnapshot[record.car_id][time_start_offset].detail_map2[
                    prop_name].add(record.value)
                carSnapshot[record.car_id][
                    time_start_offset].detail_list.append(
                    DetailItem(prop_name, record.occur_time, record.value))
        snapshot_record_list[time_start_offset].append(record)

    if add_change_event:
        add_event_from_record_list(record_list, prop_name, prop_value_data_type,
                                   1, 10)
    if add_snapshot_event:
        for snap_key in snapshot_record_list:
            rec_list = snapshot_record_list[snap_key]
            if len(rec_list) <= 1 or rec_list[0].value == rec_list[-1].value:
                continue
            add_event_from_record_list(rec_list, prop_name,
                                       prop_value_data_type, len(rec_list) - 1,
                                       len(rec_list))


def output_schema(output_path):
    val = """<?xml version="1.0" encoding="ISO-8859-1"?>
<PMML version="3.0"
  xmlns="http://www.dmg.org/PMML-3-0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema_instance" >
    <labels>
    """ + "".join(schema) + "</labels></PMML>"
    f = open(output_path, 'w')
    f.write(val)
    f.close()


def get_car_id_with_snapshot(car, snapshot_time):
    return car + "-" + time.strftime("%Y%m%d%H%M%S",
                                     time.localtime(snapshot_time))


def output_snapshot(vertex_path, edge_path):
    car_file = open(vertex_path + "/car.csv", 'w')
    car_edge_file = open(edge_path + "/car_edge.csv", "w")
    for car in carSnapshot:
        item_list = list()
        for snapshot_time in carSnapshot[car]:
            vid = get_car_id_with_snapshot(car, snapshot_time)
            snapshot = snapshot_time
            item_list.append((vid, snapshot_time))
            duration = intervals
            car_file.write(vid + ",car," + car + "," + timestamp2csv_time(
                snapshot) + "," + str(duration) + "\n")
        item_list.sort(key=lambda x: x[1])
        for (x, y) in zip(item_list[0:-1], item_list[1:]):
            if y[1] - x[1] > intervals:
                continue
            car_edge_file.write(x[0] + "," + y[0] + ",next\n")
    car_file.close()
    car_edge_file.close()
    snapshot_data_file = open(vertex_path + "/snapshot_data.csv", 'w')
    snapshot_file = open(edge_path + "/snapshot.csv", "w")
    old_prop_data = list()
    for i in range(0, 20):
        old_prop_data.append("")
    for car in carSnapshot:
        for snapshot_time in carSnapshot[car]:
            car_id = get_car_id_with_snapshot(car, snapshot_time)
            snapshot_item = carSnapshot[car][snapshot_time]
            snapshot_id = car_id + "-snapshot"
            prop_list = list()
            for i in range(0, len(snapshotItem)):
                if i in snapshot_item.prop_list:
                    prop_list.append(snapshot_item.prop_list[i])
                    old_prop_data[i] = snapshot_item.prop_list[i]
                else:
                    prop_list.append(old_prop_data[i])
            snapshot_file.write(
                car_id + "," + snapshot_id + ",snapshot," + timestamp2csv_time(
                    snapshot_time) + "\n")
            snapshot_data_file.write(
                snapshot_id + ",snapshotData," + ",".join(prop_list) + "\n")
    snapshot_file.close()
    snapshot_data_file.close()

    detail_data_file = open(vertex_path + "/detail_data.csv", 'w')
    detail_edge_file = open(edge_path + "/detail_edge.csv", "w")
    for car in carSnapshot:
        for snapshot_time in carSnapshot[car]:
            car_id = get_car_id_with_snapshot(car, snapshot_time)
            snapshot_item = carSnapshot[car][snapshot_time]
            for detail in snapshot_item.detail_list:
                if isinstance(detail, DetailItem):
                    detail_id = get_car_id_with_snapshot(car,
                                                         detail.timestamp) + "-" + detail.type
                    line = detail_id + ",snapshotDetail," + detail.type + "," + timestamp2csv_time(
                        detail.timestamp) + "," + str(
                        detail.value) + "," + detail.description + "\n"
                    line2 = car_id + "," + detail_id + ",snapshot," + timestamp2csv_time(
                        detail.timestamp) + "\n"
                    detail_data_file.write(line)
                    detail_edge_file.write(line2)
    detail_data_file.close()
    detail_edge_file.close()

    event_file = open(vertex_path + "/event.csv", 'w')
    occur_file = open(edge_path + "/occur.csv", "w")
    for car in carSnapshot:
        for snapshot_time in carSnapshot[car]:
            car_id = get_car_id_with_snapshot(car, snapshot_time)
            snapshot_item = carSnapshot[car][snapshot_time]
            for event in snapshot_item.event_list:
                if isinstance(event, EventItem):
                    event_id = get_car_id_with_snapshot(car,
                                                        event.timestamp) + "-" + event.type + "-" + str(
                        int(event.duration))
                    description = event.type + u"变化了" + str(
                        event.to_value - event.from_value) + u"至" + str(
                        event.to_value)
                    line = event_id + ",event," + event.type + "," + timestamp2csv_time(
                        event.from_timestamp) + "," + timestamp2csv_time(
                        event.timestamp) + "," + str(
                        event.duration) + "," + str(
                        event.from_value) + "," + str(
                        event.to_value) + "," + description + "\n"
                    event_file.write(line)
                    line2 = car_id + "," + event_id + ",occur," + timestamp2csv_time(
                        event.timestamp) + "\n"
                    occur_file.write(line2)
    event_file.close()
    occur_file.close()


def parse_csv_to_graph(csv_dir):
    schema.append(carVertexSchema)
    schema.append(snapshotSchema)
    schema.append(occurSchema)
    schema.append(eventSchema)
    schema.append(snapshotDetailSchema)

    add_prop(u"扭矩", os.path.join(csv_dir, "can数据扭矩.csv"), 3, 2, 5, "int", False,
             True, add_snapshot_details=False)
    add_prop(u"转速", os.path.join(csv_dir, "can数据转速.csv"), 3, 2, 5, "int", False,
             True, add_snapshot_details=True)
    add_prop(u"发动机油温", os.path.join(csv_dir, "can数据发动机油温.csv"), 3, 2, 5, "double",
             False, True, add_snapshot_details=False)
    add_prop(u"燃油累积使用量", os.path.join(csv_dir, "can数据燃油累积使用量.csv"), 3, 2, 5,
             "double", False, True)
    add_prop(u"瞬时油耗", os.path.join(csv_dir, "can数据瞬时油耗.csv"), 3, 2, 5, "double",
             True, add_snapshot_details=False)
    add_prop(u"点火开关", os.path.join(csv_dir, "开关量数据.csv"), 2, 1, 24, "int", True,
             add_snapshot_details=True)
    add_prop(u"空调状态", os.path.join(csv_dir, "开关量数据.csv"), 2, 1, 19, "int", True)
    add_prop(u"油门踏板", os.path.join(csv_dir, "开关量数据.csv"), 2, 1, 4, "int", True,
             add_snapshot_details=True)
    add_prop(u"刹车", os.path.join(csv_dir, "开关量数据.csv"), 2, 1, 5, "int", True,
             add_snapshot_details=True)
    add_prop(u"手刹", os.path.join(csv_dir, "开关量数据.csv"), 2, 1, 6, "int", True,
             add_snapshot_details=True)
    add_prop(u"倒车", os.path.join(csv_dir, "开关量数据.csv"), 2, 1, 8, "int", True,
             add_snapshot_details=True)

    snapshotDataSchemaOut = snapshotDataSchema.replace("{{propertiesList}}",
                                                       ''.join(
                                                           snapshotItem))
    schema.append(snapshotDataSchemaOut)
    graph_dir = os.path.join(csv_dir, "graph")
    if not os.path.exists(graph_dir):
        os.mkdir(graph_dir)

    schema_path = os.path.join(graph_dir, "schema.xml")
    output_schema(schema_path)

    vertex_dir = os.path.join(graph_dir, "vertex")
    if not os.path.exists(vertex_dir):
        os.mkdir(vertex_dir)

    edge_dir = os.path.join(graph_dir, "edge")
    if not os.path.exists(edge_dir):
        os.mkdir(edge_dir)

    output_snapshot(vertex_dir, edge_dir)
    return graph_dir
